/*
 * Codificacion.cpp
 *
 *  Created on: 26/11/2011
 *      Author: putaro
 */

#include "Codificacion.h"
#include <cmath>

/*
 * Pre: El parámetro número es el valor que se quiere codificar como código Delta y el
 * parámetro generador es la instancia de la clase GeneradorPunteros la cual permite
 * escribir en un archivo el resultado de la codificación.
 * Post: Se ha guardado en el archivo asocido al parámetro generador el resultado de la
 * codificación
 */
void Codificacion::codificarDelta(const unsigned int numero, GeneradorPunteros &generador){
	unsigned int cantBitsBin = 0;
	unsigned int binario = 0;
	cantBitsBin = floor(log2(numero));
	//codifico la parte unaria
	Codificacion::codificarGamma(1+cantBitsBin,generador);
	//codifico el resto del número
	binario = numero - pow(2,cantBitsBin);
	for(;cantBitsBin > 0;cantBitsBin--) {
		generador.guardarBit((numero>>(cantBitsBin-1))&1);
	}
}

/*
 * Pre: El parámetro punterosHandler es la instancia de la clase PunterosHandler la cual permite
 * leer los números codificados en código Delta en un archivo.
 * Post: Se ha retornado el resultado de la decodificación
*/
unsigned int Codificacion::decodificarDelta(PunterosHandler &punterosHandler){
	unsigned int valorGamma = 0;
	unsigned int cantidadBitsBinario = 0;
	unsigned int valorBinario = 0;
	valorGamma = Codificacion::decodificarGamma(punterosHandler);
	cantidadBitsBinario = valorGamma-1;
	for( unsigned int i = cantidadBitsBinario; i>0 ; i--){
		if(punterosHandler.getBit())
			valorBinario+=pow(2,(i-1));
	}
	return pow(2,cantidadBitsBinario) + valorBinario;
}

/*
 * Pre: El parámetro número es el valor que se quiere codificar como código Gamma y el
 * parámetro generador es la instancia de la clase GeneradorPunteros la cual permite
 * escribir en un archivo el resultado de la codificación.
 * Post: Se ha guardado en el archivo asocido al parámetro generador el resultado de la
 * codificación
 */
void Codificacion::codificarGamma(const unsigned int numero, GeneradorPunteros &generador) {
	unsigned int cantBitsBin = 0;
	unsigned int binario = 0;
	cantBitsBin = floor(log2(numero));
	//codifico la parte unaria
	Codificacion::codificarUnario(1+cantBitsBin,generador);
	//codifico el resto del número
	binario = numero - pow(2,cantBitsBin);
	for(;cantBitsBin > 0;cantBitsBin--) {
		generador.guardarBit((numero>>(cantBitsBin-1))&1);
	}
}

/*
 * Pre: El parámetro punterosHandler es la instancia de la clase PunterosHandler la cual permite
 * leer los números codificados en código Gamma en un archivo.
 * Post: Se ha retornado el resultado de la decodificación
*/
unsigned int Codificacion::decodificarGamma(PunterosHandler &punterosHandler){
	unsigned int valorUnario = 0;
	unsigned int cantidadBitsBinario = 0;
	unsigned int valorBinario = 0;
	valorUnario = Codificacion::decodificarUnario(punterosHandler);
	cantidadBitsBinario = valorUnario-1;
	for( unsigned int i = cantidadBitsBinario; i>0 ; i--){
		if(punterosHandler.getBit())
			valorBinario+=pow(2,(i-1));
	}
	return pow(2,cantidadBitsBinario) + valorBinario;
}

/*
 * Pre: El parámetro número es el valor que se quiere codificar como código Unario y el
 * parámetro generador es la instancia de la clase GeneradorPunteros la cual permite
 * escribir en un archivo el resultado de la codificación.
 * Post: Se ha guardado en el archivo asocido al parámetro generador el resultado de la
 * codificación
 */
void Codificacion::codificarUnario(const unsigned int numero , GeneradorPunteros &generador){
	unsigned int auxiliar = numero;
	auxiliar--;
	for(;auxiliar > 0;auxiliar--){
		generador.guardarBit(1);
	}
	generador.guardarBit(0);
}

/*
 * Pre: El parámetro punterosHandler es la instancia de la clase PunterosHandler la cual permite
 * leer los números codificados en código Unario en un archivo.
 * Post: Se ha retornado el resultado de la decodificación
*/
unsigned int Codificacion::decodificarUnario(PunterosHandler &punterosHandler){
	unsigned int retorno = 1;
	while(punterosHandler.getBit()){
		retorno++;
	}
	return retorno;
}
